#!/usr/bin/env python
# encoding: utf-8
# @author: Lin Han
# @contact: voldemort22@126.com
# @file: calculate.py
# @time: 2021/4/23 13:18
# @desc:
import json
from typing import Union, Dict, List

import json5
import numpy as np


# from sklearn.metrics.pairwise import cosine_similarity


def read_json(json_file: str) -> Dict:
    """
    读取Json文件
    :param json_file: Json文件路径
    """
    if json_file.endswith('.json'):
        try:
            return json.load(open(json_file, encoding="utf-8", errors='ignore'))
        except ValueError:
            return json.load(open(json_file, encoding="gbk", errors='ignore'))
    else:
        try:
            return json5.load(open(json_file, encoding="utf-8", errors='ignore'))
        except ValueError:
            return json5.load(open(json_file, encoding="gbk", errors='ignore'))


sample = read_json("sample_ss.json")


def cosine_similarity(x, y):
    num = x.dot(y.T)
    denom = np.linalg.norm(x) * np.linalg.norm(y)
    return num / denom


def is_xyz_same(point_1: List[float], point_2: List[float]) -> bool:
    """
    - 判断两点坐标是否重合。

    :param point_1:
    :param point_2:
    :return:
    """
    point_1 = np.array(point_1)
    point_2 = np.array(point_2)
    minus_result = point_1 - point_2
    if np.all(minus_result == 0):
        return True
    else:
        return False


# def is_normal_opposite(normalLine_1: List[float], normalLine_2: List[float]) -> bool:
#     """
#     Judge if 2 normal line opposite direction.
#
#     :param normalLine_1:
#     :param normalLine_2:
#     """
#     normalLine_1 = np.array(normalLine_1)
#     normalLine_2 = np.array(normalLine_2)
#     plus_result = normalLine_1 + normalLine_2
#     if np.all(plus_result == 0):
#         return True
#     else:
#         return False

def is_normal_opposite(normalLine_1: List[float], normalLine_2: List[float]) -> bool:
    """
    - 判断两根法线是否相反（计算余弦相似度是否为-1）

    :param normalLine_1:
    :param normalLine_2:
    """
    normalLine_1 = np.array(normalLine_1)
    normalLine_2 = np.array(normalLine_2)
    similarity = cosine_similarity(normalLine_1, normalLine_2)
    if similarity == -1:
        return True
    else:
        return False


def pointModels_match(pointModels_1: List[dict], pointModels_2: List[dict]) -> list:
    """
    - 判断并输出两组点组包含关系

    Remember that length of pointModels_1 should be less or equal to pointModels_2. (Not neccessary now)

    :param pointModels_1:
    :param pointModels_2:
    """
    result_list = []
    for i in pointModels_1:
        for j in pointModels_2:
            if is_xyz_same(i["Coordinate"], j["Coordinate"]):
                result_list.append({i["Name"]: j["Name"]})

    return result_list


def groups_match(groups_1: List[dict], groups_2: List[dict]) -> list:
    """
    - 判断并输出两个零件中点组的包含关系

    :param groups_1:
    :param groups_2:
    :return:
    """
    result = []
    for i in groups_1:
        for j in groups_2:
            if is_normal_opposite(i["NormalLine"], j["NormalLine"]):
                match_point_group = pointModels_match(i["PointModels"], j["PointModels"])
                if len(match_point_group) > 0:
                    result.append({i["Group"]: j["Group"], "match_point_group": match_point_group})

    return result


if __name__ == '__main__':
    match = []

    groups_amount = len(sample)
    for i in range(groups_amount):
        for j in range(i + 1, groups_amount):
            match_item = groups_match(sample[i]["AssemblyGroups"], sample[j]["AssemblyGroups"])
            if len(match_item) > 0:
                match.append({sample[i]["PartName"]: sample[j]["PartName"], "match_group": match_item})

    print(match)
